
const textWriteTime = 0.1;
const textChangeTime = 100;

class GameUtils {

    public static getCamera(): egret3d.Camera {
        let camGo = paper.GameObject.findWithTag("MainCamera");
        if (!camGo)
            camGo = paper.GameObject.find("Camera");
        let cam;
        if (!camGo)
            cam = egret3d.Camera.main;
        else {
            cam = camGo.getComponent(egret3d.Camera);
            if (!cam) {
                cam = camGo.addComponent(egret3d.Camera);
            }
        }
        cam.order = 0;
        return cam;
    }

	/**
	 * 获取一个向量的垂直方向
	 */
    public static GetVerticalDir(_dir: egret3d.Vector3): egret3d.Vector3 {
        //（_dir.x,_dir.z）与（？，1）垂直，则_dir.x * ？ + _dir.z * 1 = 0
        if (_dir.z == 0) {
            return egret3d.Vector3.create(0, 0, -1);
        }
        else {
            return egret3d.Vector3.create(-_dir.z / _dir.x, 0, 1).normalize();
        }
    }
    public static array3String(arr: any[]): string {
        return '[' + arr[0] + ',' + arr[1] + ',' + arr[2] + ']';
    }
    public static quaternionString(q4: Readonly<egret3d.IVector4>): string {
        return '(' + q4.x.toFixed(2) + ',' + q4.y.toFixed(2) + ',' + q4.z.toFixed(2) + ',' + q4.w.toFixed(2) + ')';
    }
    public static vector2String(v3: Readonly<egret3d.IVector2>): string {
        return '(' + v3.x.toFixed(2) + ',' + v3.y.toFixed(2) + ')';
    }
    public static vector3String(v3: Readonly<egret3d.IVector3>): string {
        return '(' + v3.x.toFixed(2) + ',' + v3.y.toFixed(2) + ',' + v3.z.toFixed(2) + ')';
    }
    public static colorString(clr: egret3d.Color): string {
        return '(' + clr.r.toFixed(2) + ',' + clr.g.toFixed(2) + ',' + clr.b.toFixed(2) + ',' + clr.a.toFixed(2) + ')';
    }

    public static checkLog(name: string, v: any): boolean {
        if (v === null)
            console.log(name + ' is null');
        else if (v === undefined)
            console.log(name + ' is undefined');
        else {
            console.log(name + ' is ' + v);
            return true;
        }
        return false;
    }

    /**
     * 判定是否为空对象、空字符 
     */
    public static isEmpty(obj: any) {
        if (obj === null || obj === undefined || obj === NaN) {
            return true;
        }
        if (typeof (obj) == 'string') {
            if (obj == '') {
                return true;
            }
        }
        return false;
    }

    /**
     * 随机枚举对象(非0，默认0位随机的值)
     */
    public static randomEnum(_enum) {
        let _keyArray = [];
        for (var key in _enum) {
            _keyArray.push(key);
        }
        let _key = Math.floor(Math.random() * (_keyArray.length - 1) / 2);
        _key = _key == 0 ? 1 : _key;
        return _key;
    }

    /**
     * 获取当前时间戳(精确到秒)(计算过差值的)
     */
    public static getCurrentTime() {
        return Math.round(new Date().getTime()) - GameUtils.serverToCurrentDt;
    }

    /**
     * 服务器与本地时间差
     */
    public static serverToCurrentDt = 0;

    /**
    * 获取当前时间戳(精确到秒)
    */
    public static setServerTimeToCurrentDT(time: number) {
        GameUtils.serverToCurrentDt = Math.round(new Date().getTime() / 1000) - time;
    }

    /**
     * 获取00:00:00格式时间
     */
    public static transformTime(num) {
        if (num < 0) {
            num = 0;
        }
        var h = Math.floor(num / 3600) < 10 ? '0' + Math.floor(num / 3600) : Math.floor(num / 3600);
        var m = Math.floor((num / 60 % 60)) < 10 ? '0' + Math.floor((num / 60 % 60)) : Math.floor((num / 60 % 60));
        var s = Math.floor((num % 60)) < 10 ? '0' + Math.floor((num % 60)) : Math.floor((num % 60));
        return h + ":" + m + ":" + s;
    }

    /**
     * 深度查找特定名称物体
     */
    public static findGameObjectWithNameInChildren(obj: egret3d.Transform, name: string): egret3d.Transform {
        if (name && name.length > 0) {
            let trans = obj.gameObject.getComponentsInChildren(egret3d.Transform);
            for (let i = 0; i < trans.length; i++) {
                if (trans[i].gameObject.name === name) {
                    return trans[i];
                }
            }
        }
        return null;
    }

    /**
     * 获取对象在数组中的索引
     */
    public static getObjectIndexInArray(obj: any, array: any[]) {
        if (array.length > 0) {
            for (let i = 0; i < array.length; i++) {
                let element = array[i];
                if (array[i].uuid == obj.uuid) {
                    return i;
                }
            }
        }
        return null;
    }

    /**
     * 根据名称创建prefab实例
     */
    public static createPrefab(res: string): paper.GameObject {
        const prefab = RES.getRes(res) as egret3d.Prefab;
        if (!prefab) {
            console.warn('RES.getRes failed: ' + res);
            return null;
        }
        let go = prefab.createInstance();
        return go;
    }
    public static createSphere(x, y, z, scale?: number, color?: egret3d.Color): paper.GameObject {
        let go = paper.GameObject.create("aim");
        let meshFilter = go.addComponent(egret3d.MeshFilter);
        meshFilter.mesh = egret3d.DefaultMeshes.SPHERE;
        let renderer = go.addComponent(egret3d.MeshRenderer);

        let material = egret3d.Material.create(egret3d.DefaultShaders.MATERIAL_COLOR);
        if (color)
            material.setColor('diffuse', color);
        else
            material.setColor('diffuse', egret3d.Color.WHITE);
        renderer.material = material;

        go.transform.setPosition(x, y, z);
        if (!!scale)
            go.transform.setLocalScale(scale, scale, scale);
        return go;
    }
    public static createLine() {
        let mat = new egret3d.Material(egret3d.DefaultShaders.LINEDASHED);
    }
    /**
     * 从父级移除node
     */
    public static removeFromParent(display: egret.DisplayObject) {
        display && display.parent && display.parent.removeChild(display);
    }

    /**
     * 设置Timeout
     */
    public static setTimeout<T>(fn: (self: T, ...args) => void, thisObj: any, duration: number, ...args: any[]): number {
        let id = egret.setTimeout(fn, thisObj, duration, ...args);
        if (thisObj) {
            if (!thisObj["__timeOutIDs__"]) {
                thisObj["__timeOutIDs__"] = [];
            }
            thisObj["__timeOutIDs__"].push(id);
        }
        return id;
    }

    /**
    * 设置Interval循环
    */
    public static setInterval<T>(listener: (self: T, ...arg) => void, thisObject: T, delay: number, ...args: any[]): number {
        let id = egret.setInterval(listener, thisObject, delay, ...args);
        if (thisObject) {
            if (!thisObject["__intervalIDs__"]) {
                thisObject["__intervalIDs__"] = [];
            }
            thisObject["__intervalIDs__"].push(id);
        }
        return id;
    }

    /**
    * 清除所有Interval循环
    */
    public static clearAllInterval(thisObj) {
        if (thisObj && thisObj["__intervalIDs__"]) {
            thisObj["__intervalIDs__"].forEach(id => {
                egret.clearInterval(id);
            });
        }
    }

    /**
     * 清除所有Timeout
     */
    public static clearAllTimeout(thisObj) {
        if (thisObj && thisObj["__timeOutIDs__"]) {
            thisObj["__timeOutIDs__"].forEach(id => {
                egret.clearTimeout(id);
            });
        }
    }

    static invokeCallback(cb: Function, ...optionalParams: any[]) {
        if (cb && typeof (cb) === "function") {
            cb(...optionalParams);
        }
    }

    /**
     * 获取一个数字的保留<digit>位数的小数(force强制成小数)
     */
    public static getNumToFixed(num: string, digit: number = 2, isForce: boolean = false) {
        if (num.indexOf('.') > -1 || isForce) {
            return parseFloat(num).toFixed(digit);
        }
        else {
            return parseInt(num);
        }
    }

    /**
    * 获取一个数字的保留<digit>位数的百分数(force强制成小数)
    */
    public static getNumToFixedPercent(num: string, digit: number = 2, isForce: boolean = false) {
        let _num = parseFloat(num) * 100;
        if (_num.toString().indexOf('.') > -1 || isForce) {
            return _num.toFixed(digit) + "%";
        }
        else {
            return _num + "%";
        }
    }


    /**
     * 文字打字机效果
     */
    public static labelToWriter(label: eui.Label, txt: string, time: number, cb: Function = null) {
        GameUtils.clearAllInterval(label);
        let _fun = () => {
            GameUtils.clearAllInterval(label);
            label.text = txt;
            if (cb) {
                cb();
            }
            label.removeEventListener(egret.TouchEvent.TOUCH_TAP, _fun, this);
        }
        label.addEventListener(egret.TouchEvent.TOUCH_TAP, _fun, this);
        let _txt = txt;
        let _speed = time * 1000 / txt.length;
        let index = 0;
        let _data = _txt.substring(0, index);
        let _timeOut = GameUtils.setInterval(function () {
            write();
        }, label, _speed);
        function write() {
            if (!label || index == txt.length) {
                index = 0;
                GameUtils.clearAllInterval(label);
                if (cb) {
                    cb();
                }
            }
            else {
                index++;
                label.text = _txt.substring(0, index);
            }
        }
    }
    // 字符串示例："文字提示，#$上面#显示"
    public static getTextFlow(txt: string): egret.ITextElement[] {
        let retArray: egret.ITextElement[] = [];
        let txtArray: string[] = txt.split("#");
        txtArray.forEach(element => {
            let _text: string;
            let _style = {};
            let index = element.indexOf("$");
            if (index === 0) {
                _style = { textColor: "0xff9600" };
                _text = element.substr(1);
            }
            else {
                _text = element;
            }
            retArray.push({ text: _text, style: _style });
        });
        return retArray;
    }

    /**
    * 富文本打字机效果
    */
    public static richTextToWriter(label: eui.Label, txt: string, time: number, cb: Function = null) {
        GameUtils.clearAllInterval(label);
        let sTemp = txt.substring(1, txt.length - 1);
        let sArray: any[] = sTemp.split(",");
        let _array = [];
        sArray.forEach(element => {
            if (element.text) {
                let _txt;
                let _style = {};
                for (let key in element) {
                    if (key != "text") {
                        _style[key] = element[key];
                    }
                }
                for (let i = 0; i < element.text.length; i++) {
                    _array.push({ text: element.text[i], style: _style });
                }
            }
        });

        let _speed = time * 1000;
        let index = 0;
        let _timeOut = GameUtils.setInterval(function () {
            write();
        }, label, _speed);
        function write() {
            if (!label || index == _array.length) {
                index = 0;
                GameUtils.clearAllInterval(label);
                if (cb) {
                    cb();
                }
            }
            else {
                index++;
                label.textFlow = <Array<egret.ITextElement>>_array.slice(0, index);
            }
        }
    }

    /**
     * 文字老虎机效果
     */
    public static labelToChange(label: eui.Label, numStart: number = null, numEnd: number, time: number, cb: Function = null) {
        GameUtils.clearAllInterval(label);
        let _start = numStart != null ? numStart : parseInt(label.text);
        label.text = _start + "";

        let _speed = (numEnd - _start) / (time * 1000 / textChangeTime);
        let index = _start;
        let isUp = (numEnd - _start) > 0;

        GameUtils.setInterval(function () {
            change();
        }, label, textChangeTime);

        function change() {
            if (!label || isUp ? (index >= numEnd) : (index <= numEnd)) {
                label.text = numEnd + "";
                GameUtils.clearAllInterval(label);
                if (cb) {
                    cb();
                }
            }
            else {
                index += _speed;
                label.text = Math.ceil(index) + "";
            }
        }
    }

    /**
     * 获取屏幕的宽度(基于UI,固定640)
     */
    public static getSceneWidth() {
        return egret3d.stage.viewport.w;
    }

    /**
     * 获取屏幕高度(基于UI,1136按比例缩放)
     */
    public static getSceneHeigth() {
        return egret3d.stage.viewport.h;
    }

    /**
     * 获取2D UI缩放的比例
     */
    public static get2DRenderScaler() {
        if (SceneManager.instance.uiRoot) {
            return SceneManager.instance.uiRoot.getComponent(egret3d.Egret2DRenderer).scaler;
        }
        return null;
    }

    /**
     * 获取外部图片(url)
     */
    public static loadImage(url: string, node: eui.Image) {
        let imgLoader = new egret.ImageLoader();
        imgLoader.crossOrigin = "anonymous";
        imgLoader.once(egret.Event.COMPLETE, function (evt: egret.Event) {
            if (evt.currentTarget.data) {
                egret.log("加载图片成功: " + evt.currentTarget.data);
                // 创建一个容器
                let container = new egret.DisplayObjectContainer();
                let texture = new egret.Texture();
                texture.bitmapData = evt.currentTarget.data;
                let bitmap = new egret.Bitmap(texture);
                // 将头像放到容器内
                container.addChild(bitmap);
                let renderTexture: egret.RenderTexture = new egret.RenderTexture();
                // 将容器绘制成纹理
                renderTexture.drawToTexture(container);
                // 将纹理赋给头像组件(eui.Image)
                node.source = renderTexture;
                // 释放纹理
                bitmap.texture.dispose();
                bitmap = null;
            }
        }, this);
        imgLoader.once(egret.IOErrorEvent.IO_ERROR, function (evt: egret.Event) {
            egret.log("加载图片失败");
        }, this);
        if (url) {
            imgLoader.load((<string>url).replace(/[\\]/g, ''));// 去除链接中的转义字符‘\’
        }
    }

    /**
     * 取得url参数
     */
    public static getUrlParam(name) {
        var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)"); // 构造一个含有目标参数的正则表达式对象
        var r = window.location.search.substr(1).match(reg);  // 匹配目标参数
        if (r != null) return decodeURIComponent(r[2]); return null; // 返回参数值
    }

    /**
     * 获取格式化的字符串
     */
    public static stringFormat(...args) {
        if (arguments.length == 0)
            return null;
        var str = arguments[0];
        for (var i = 1; i < arguments.length; i++) {
            var re = new RegExp('\\{' + (i - 1) + '\\}', 'gm');
            str = str.replace(re, arguments[i]);
        }
        return str;
    }

    // 数字转换中文
    public static chnNumChar = ["零", "一", "二", "三", "四", "五", "六", "七", "八", "九"];
    public static chnUnitSection = ["", "万", "亿", "万亿", "亿亿"];
    public static chnUnitChar = ["", "十", "百", "千"];

    public static SectionToChinese(section) {
        var strIns = '', chnStr = '';
        var unitPos = 0;
        var zero = true;
        while (section > 0) {
            var v = section % 10;
            if (v === 0) {
                if (!zero) {
                    zero = true;
                    chnStr = GameUtils.chnNumChar[v] + chnStr;
                }
            } else {
                zero = false;
                strIns = GameUtils.chnNumChar[v];
                strIns += GameUtils.chnUnitChar[unitPos];
                chnStr = strIns + chnStr;
            }
            unitPos++;
            section = Math.floor(section / 10);
        }
        return chnStr;
    }


    /**
     * 获取圆形mask(圆环进度条遮罩)
     * @param node 被遮罩物体
     * @param angle 旋转角度
     * @param startAngle 初始角度【默认为从12点方向】
     * @param anticlockwise 如果为 true，逆时针绘制圆弧，反之，顺时针绘制。【默认为顺时针】
     */
    public static drawCircleMask(node: eui.UIComponent, angle: number, offsetY : number = 0, shape: egret.Shape = null, anticlockwise: boolean = true) {
        var _shape: egret.Shape;
        if (GameUtils.isEmpty(shape)) {
            _shape = new egret.Shape();
        }
        else {
            _shape = shape;
        }
        var w: number = node.width;
        var h: number = node.height;
        var r: number = Math.max(w, h) / 2 * 1.5;
        _shape.x = w / 2;
        _shape.y = h / 2 + offsetY;

        _shape.graphics.clear();
        _shape.graphics.beginFill(0xff0000);
        _shape.graphics.lineTo(r, 0);
        _shape.graphics.drawArc(0, 0, r, (-90 + angle) * Math.PI / 180, (-90) * Math.PI / 180, anticlockwise);
        _shape.graphics.lineTo(0, 0);
        _shape.graphics.endFill();

        return _shape;
    }

    /**
     * 更新摄像机的视口为UI框大小
     */
    public static updateViewNode(node: eui.UIComponent, camera: egret3d.Camera) {
        const point = node.localToGlobal(0, 0);
        const viewport = egret3d.stage.viewport;
        camera.pixelViewport = { x: point.x, y: point.y, w: node.width, h: node.height };
    }

    /**
     * 检测是否是刘海屏
     */
    public static checkFullScreenMobile(): boolean {
        if (GameUtils.isEmpty(GlobalManager.instance.systemInfo)) {
            return false;
        }
        if (GlobalManager.instance.systemInfo.model == "iPhone X" || GlobalManager.instance.systemInfo.screenWidth / GlobalManager.instance.systemInfo.screenHeight > 2) {
            //iphone x或者其他大于宽高比2:1的
            return true;
        }
        return false;
    }

}

// ========== 